/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/*!
  \file			txlist.h
  \date			Feb 2012
  \author		TNick

  \brief		Contains the definition for TxList class


*//*


 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Please read COPYING and README files in root folder
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
#ifndef __TXLIST_INC__
#define __TXLIST_INC__
//
//
//
//
/*  INCLUDES    ------------------------------------------------------------ */

#include	<QList>
#include	<QChar>

/*  INCLUDES    ============================================================ */
//
//
//
//
/*  CLASS    --------------------------------------------------------------- */

/**
*	@brief
*/
class TxList				{

	//
	//
	//
	//
	/*  DEFINITIONS    ----------------------------------------------------- */


#define	IDX_REFCOUNT	( 0 )
#define	IDX_LEN			( 1 )
#define	IDX_STR			( 2 )
#define	HEADER_SIZE		2
#define	FOOTER_SIZE		1
#define	EXTRA_CHARS		( HEADER_SIZE + FOOTER_SIZE )

#define	HEADER_SZ_BYTES	( sizeof(QChar) * HEADER_SIZE )
#define	OFF_REFCOUNT	( sizeof(QChar) * IDX_REFCOUNT )
#define	OFF_LEN			( sizeof(QChar) * IDX_LEN )
#define	OFF_STR			( sizeof(QChar) * IDX_STR )
#define	EXTRA_CHARS_SZ	( sizeof(QChar) * EXTRA_CHARS )


#define	REF_FIXED		0xFFFF
#define	LEN_FIXED		0xFFFF

#ifdef	OBJECTSLIB_TESTS
	friend void		TxList_Tests	( int&, int& );
#endif

	/*  DEFINITIONS    ===================================================== */
	//
	//
	//
	//
	/*  DATA    ------------------------------------------------------------ */

private:

	/**
	*	@brief	the list of names
	*/
	QList<QChar*>		names_;



	/*  DATA    ============================================================ */
	//
	//
	//
	//
	/*  FUNCTIONS    ------------------------------------------------------- */

public:


	/**
	*	@brief	constructor;
	*/
	TxList				( void );


	/**
	*	@brief	destructor; invokes clear() internally so you don't have to
	*/
	~TxList				( void );


	/**
	*	@brief	the name at index i
	*/
	inline QChar *		at			( unsigned i )
	{
		if (i >= (unsigned)names_.count() )
			return NULL;
		return names_.at( i );
	}

	/**
	*	@brief	the name at index i as an array of null-terminated QChar s
	*/
	inline QChar *		asArray			( unsigned i )
	{
		if (i >= (unsigned)names_.count() )
			return NULL;
		return names_.at( i ) + IDX_STR;
	}


	/**
	*	@brief	the name at index i as an array of null-terminated QChar s
	*/
	inline QChar *		asArray			( QChar * p_targ )
	{
		if ( names_.indexOf( p_targ ) == -1 )
			return NULL;
		return p_targ + IDX_STR;
	}


	/**
	*	@brief	the name at index i as an QString
	*/
	inline QString		asString			( unsigned i )
	{
		if (i >= (unsigned)names_.count() )
			return QString();
		QChar * p_targ = names_.at( i );
		return QString( p_targ + IDX_STR, charLen( p_targ ) );
	}

	/**
	*	@brief	the name at index i as an QString
	*/
	inline QString		asString			( QChar * p_targ )
	{
		if ( names_.indexOf( p_targ ) == -1 )
			return QString();
		return QString( p_targ + IDX_STR, charLen( p_targ ) );
	}

	/**
	*	@brief	number of names that are internally stored
	*/
	inline unsigned		count		( void )
	{ return (unsigned)names_.count( ); }


	/**
	*	@brief	get the index of a pointer
	*
	*	@return	-1 if not found, the index otherwise
	*/
	inline int			index		( QChar * p_targ )
	{ return names_.indexOf( p_targ ); }


	/**
	*	@brief	increase the reference count for a pointer
	*/
	inline void			incRef		( QChar * p_targ )
	{
#  ifndef QT_NO_DEBUG
		Q_ASSERT( names_.indexOf( p_targ ) != -1);
#  else
		if ( names_.indexOf( p_targ ) == -1) return;
#  endif
		incChRefCount( p_targ );
	}

	/**
	*	@brief	increase the reference count for a pointer
	*/
	inline void			incRef		( unsigned i )
	{
#  ifndef QT_NO_DEBUG
		Q_ASSERT( (unsigned)names_.count() > i );
#  else
		if ( (unsigned)names_.count() <= i ) return;
#  endif
		incChRefCount( names_.at( i ) );
	}



	/**
	*	@brief	decrease the reference count for a pointer
	*/
	inline void			decRef		( QChar * p_targ )
	{
#  ifndef QT_NO_DEBUG
		Q_ASSERT( names_.indexOf( p_targ ) != -1);
#  else
		if ( names_.indexOf( p_targ ) == -1) return;
#  endif
		decChRefCount( p_targ );
		if ( chRefCount( p_targ ) == 0 )
		{
			free( p_targ );
			names_.removeOne( p_targ );
		}
	}

	/**
	*	@brief	decrease the reference count for a pointer
	*/
	inline void			decRef		( unsigned i )
	{
#  ifndef QT_NO_DEBUG
		Q_ASSERT( (unsigned)names_.count() > i );
#  else
		if ( (unsigned)names_.count() <= i ) return;
#  endif
		decRef( names_.at( i ) );
	}


	/**
	*	@brief	get the reference count for a pointer
	*/
	inline unsigned		refCount	( QChar * p_targ )
	{
#  ifndef QT_NO_DEBUG
		Q_ASSERT( names_.indexOf( p_targ ) != -1);
#  else
		if ( names_.indexOf( p_targ ) == -1) return 0;
#  endif
		return chRefCount( p_targ );
	}

	/**
	*	@brief	get the reference count for a pointer
	*/
	inline unsigned		refCount	( unsigned i )
	{
#  ifndef QT_NO_DEBUG
		Q_ASSERT( (unsigned)names_.count() > i );
#  else
		if ( (unsigned)names_.count() <= i ) return 0;
#  endif
		return chRefCount( names_.at( i ) );
	}


	/**
	*	@brief	get the size of the array without management bytes
	*/
	inline unsigned		getSize		( QChar * p_targ )
	{
#  ifndef QT_NO_DEBUG
		Q_ASSERT( names_.indexOf( p_targ ) != -1);
#  else
		if ( names_.indexOf( p_targ ) == -1) return 0;
#  endif
		return charLen( p_targ );
	}

	/**
	*	@brief	get the size of the array without management bytes
	*/
	inline unsigned		getSize		( unsigned i )
	{
#  ifndef QT_NO_DEBUG
		Q_ASSERT( (unsigned)names_.count() > i );
#  else
		if ( (unsigned)names_.count() <= i ) return 0;
#  endif
		return charLen( names_.at( i ) );
	}



	/**
	*	@brief	removes an element even if its reference count is not 0
	*
	*	bf stands for brute force :)
	*/
	inline void			bfRemove		( QChar * p_targ )
	{
#  ifndef QT_NO_DEBUG
		Q_ASSERT( names_.indexOf( p_targ ) != -1);
#  else
		if ( names_.indexOf( p_targ ) == -1) return;
#  endif
		free( p_targ );
		names_.removeOne( p_targ );
	}


	/**
	*	@brief	removes an element even if its reference count is not 0
	*/
	inline void			bfRemove		( unsigned i )
	{
#  ifndef QT_NO_DEBUG
		Q_ASSERT( (unsigned)names_.count() > i );
#  else
		if ( (unsigned)names_.count() <= i ) return;
#  endif
		bfRemove( names_.at( i ) );
	}


	/**
	*	@brief	removes all the elements inside
	*/
	void				clear			( void );


	/**
	*	@brief	add a name to the internal list
	*
	*	It is assummed that the name was properly formatted (the reference
	*	count, the number of characters and ending NULL were placed properly).
	*
	*	The library takes the ownership of the buffer that must have been
	*	allocated using malloc().
	*
	*
	*/
	inline unsigned		append		( QChar * p_new )
	{
		Q_ASSERT( isCharNullTerminated(p_new) );
		names_.append( p_new );
		return (unsigned)names_.count( ) - 1;
	}


	/**
	*	@brief	add a name to the internal list
	*
	*	The function will create a new buffer and will copy the content to it.
	*
	*	The reference count is set to 1, assuming that the caller will use
	*	the returned pointer.
	*/
	QChar *				append			( unsigned & index, QString s_tx );


	/**
	*	@brief	add a name to the internal list
	*
	*	The function will create a new buffer and will copy the content to it.
	*
	*	The reference count is set to 1, assuming that the caller will use
	*	the returned pointer.
	*/
	QChar *				append			( QString & s_tx, unsigned & index );


	/**
	*	@brief	add a name to the internal list
	*
	*	The function will create a new buffer and will copy the content to it.
	*
	*	The reference count is set to 1, assuming that the caller will use
	*	the returned pointer.
	*/
	QChar *				append			( const char * p_s_tx, unsigned & index );



	/**
	*	@brief	finds given string in the table
	*
	*	The function simply binary compares the content of the buffer
	*	from the string with internal buffers.
	*
	*	@param	s_tx	the text to search
	*	@param	index	the index of found buffer, in case of success
	*
	*	@return	NULL if not found or pointer to the buffer
	*/
	inline QChar *		find			( unsigned & index, QString s_tx )
	{ return find( s_tx, index ); }

	/**
	*	@brief	finds given string in the table
	*
	*	The function simply binary compares the content of the buffer
	*	from the string with internal buffers.
	*
	*	@param	s_tx	the text to search
	*	@param	index	the index of found buffer, in case of success
	*
	*	@return	NULL if not found or pointer to the buffer
	*/
	QChar *				find			( QString & s_tx, unsigned & index );


	/**
	*	@brief	finds given string in the table
	*
	*	The function simply binary compares the content of the buffer
	*	that is provided with internal buffers.
	*
	*	@param	s_tx	the text to search
	*	@param	index	the index of found buffer, in case of success
	*
	*	@return	NULL if not found or pointer to the buffer
	*/
	QChar *				find			(
			const char *		s_tx,
			unsigned &			index,
			int					s_len = -1
			);






	/**
	*	@brief	add a name to the internal list if not already there
	*
	*	If the name is not found inside the list the function will
	*	create a new buffer and will copy the content to it.
	*
	*	The reference count is set to 1 or increased, as it is assumed that
	*	the caller will use the returned pointer.
	*/
	inline QChar *		addUniq			( unsigned & index, QString s_tx )
	{ return addUniq( s_tx, index ); }


	/**
	*	@brief	add a name to the internal list if not already there
	*
	*	If the name is not found inside the list the function will
	*	create a new buffer and will copy the content to it.
	*
	*	The reference count is set to 1 or increased, as it is assumed that
	*	the caller will use the returned pointer.
	*/
	QChar *				addUniq			( QString & s_tx, unsigned & index );


	/**
	*	@brief	add a name to the internal list if not already there
	*
	*	If the name is not found inside the list the function will
	*	create a new buffer and will copy the content to it.
	*
	*	The reference count is set to 1 or increased, as it is assumed that
	*	the caller will use the returned pointer.
	*/
	QChar *				addUniq			( const char * p_s_tx, unsigned & index );










private:

	/**
	*	@brief	get the reference count of a string in QChar form
	*/
	static inline unsigned	chRefCount	( QChar * p_in )
	{ return (unsigned)(p_in + IDX_REFCOUNT)->unicode(); }


	/**
	*	@brief	increase the reference count of a string in QChar form
	*/
	static inline void	incChRefCount	( QChar * p_in )
	{
		if ( chRefCount( p_in ) == REF_FIXED ) return;
		*(p_in + IDX_REFCOUNT) = (p_in + IDX_REFCOUNT)->unicode() + 1;
	}


	/**
	*	@brief	decrease the reference count of a string in QChar form
	*/
	static inline void	decChRefCount	( QChar * p_in )
	{
		Q_ASSERT( p_in != NULL );
		if ( chRefCount( p_in ) == REF_FIXED ) return;
		*(p_in + IDX_REFCOUNT) = (p_in + IDX_REFCOUNT)->unicode() - 1;
	}


	/**
	*	@brief	set the reference count of a string in QChar form
	*/
	static inline void	setChRefCount	( QChar * p_in, unsigned new_ref )
	{
		Q_ASSERT( p_in != NULL );
		Q_ASSERT( ( new_ref & ( ~REF_FIXED ) ) == 0 );
		*(p_in + IDX_REFCOUNT) = (quint16)new_ref;
	}


	/**
	*	@brief	get the lenght of a string in QChar form
	*
	*	This includes only actual text; no count, reference count or
	*	terminating 0 element.
	*/
	static inline unsigned	charLen	( QChar * p_in )
	{
		Q_ASSERT( p_in != NULL );
		return (unsigned)(p_in + IDX_LEN)->unicode();
	}

	/**
	*	@brief	set the lenght of a string in QChar form
	*/
	static inline void	setCharLen	( QChar * p_in, unsigned new_len )
	{
		Q_ASSERT( p_in != NULL );
		Q_ASSERT( ( new_len & ( ~LEN_FIXED ) ) == 0 );
		*(p_in + IDX_LEN) = (quint16)new_len;
	}


	/**
	*	@brief	check that last character is NULL
	*/
	static inline bool	isCharNullTerminated	( QChar * p_in )
	{
		Q_ASSERT( p_in != NULL );
		return ( *( p_in + IDX_STR + charLen( p_in ) ) == 0 );
	}


	/*  FUNCTIONS    ======================================================= */
	//
	//
	//
	//

};	/*	class TxList	*/

/*  CLASS    =============================================================== */
//
//
//
//

#ifdef	OBJECTSLIB_TESTS
void				TxList_Tests					(
		int & performed, int & succeded );
#endif

#endif // __TXLIST_INC__
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
